package com.itheima.pinda.authority.biz.service.auth.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.itheima.pinda.auth.server.utils.JwtTokenServerUtils;
import com.itheima.pinda.auth.utils.JwtUserInfo;
import com.itheima.pinda.auth.utils.Token;
import com.itheima.pinda.authority.biz.service.auth.ResourceService;
import com.itheima.pinda.authority.biz.service.auth.UserService;
import com.itheima.pinda.authority.dto.auth.LoginDTO;
import com.itheima.pinda.authority.dto.auth.ResourceQueryDTO;
import com.itheima.pinda.authority.dto.auth.UserDTO;
import com.itheima.pinda.authority.entity.auth.Resource;
import com.itheima.pinda.authority.entity.auth.User;
import com.itheima.pinda.base.R;
import com.itheima.pinda.common.constant.CacheKey;
import com.itheima.pinda.database.mybatis.conditions.query.LbqWrapper;
import com.itheima.pinda.database.mybatis.conditions.update.LbuWrapper;
import com.itheima.pinda.dozer.DozerUtils;
import com.itheima.pinda.exception.BizException;
import com.itheima.pinda.exception.code.ExceptionCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.oschina.j2cache.CacheChannel;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description: 认证管理
 * @Author: ysf
 * @CreateTime: 2024-11-13  15:02
 * @Version: 1.0
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class AuthManager {

    final JwtTokenServerUtils jwtTokenServerUtils;
    final UserService userService;
    final ResourceService resourceService;
    final DozerUtils dozer;
    final CacheChannel cacheChannel;

    /**
     * 认证账号和密码
     *
     * @param account
     * @param password
     * @return R<LoginDTO>
     */
    public R<LoginDTO> login(String account, String password) {
        //1、校验账户和密码
        R<User> result = checkUser(account, password);
        if (result.getIsError()) {
            return R.fail(result.getCode(), result.getMsg());
        }

        User user = result.getData();

        //2、生成token
        Token token = this.generateUserToken(user);

        //3、查询用户拥有的资源权限
        List<Resource> resourceList = this.resourceService.
                findVisibleResource(ResourceQueryDTO.builder().userId(user.getId()).build());

        //4、用户对应权限：筛选出资源编码给前端
        List<String> permissionList = null;
        //5、用户对应权限：筛选出method+url给后端网关使用，并进行缓存
        List<String> visibleResource = null;

        if (resourceList != null && resourceList.size() > 0) {
            permissionList = resourceList.stream()
                    .map(Resource::getCode)
                    .collect(Collectors.toList());

            visibleResource = resourceList.stream()
                    .map((resource) -> {
                        return resource.getMethod() + resource.getUrl();
                    })
                    .collect(Collectors.toList());
        }
        //缓存
        cacheChannel.set(CacheKey.USER_RESOURCE, user.getId().toString(), visibleResource);

        //5、封装返回数据
        LoginDTO loginDTO = LoginDTO.builder()
                .user(this.dozer.map(user, UserDTO.class))
                .token(token)
                .permissionsList(permissionList)
                .build();

        return R.success(loginDTO);
    }

    /**
     * 生成token
     *
     * @param user
     * @return Token
     */
    final Token generateUserToken(User user) {
        //用户信息封装到JwtUserInfo
        JwtUserInfo jwtUserInfo = new JwtUserInfo();
        jwtUserInfo.setUserId(user.getId());
        jwtUserInfo.setName(user.getName());
        jwtUserInfo.setAccount(user.getAccount());
        jwtUserInfo.setOrgId(user.getOrgId());
        jwtUserInfo.setStationId(user.getStationId());
        //生成token
        Token token = jwtTokenServerUtils.generateUserToken(jwtUserInfo, null);
        return token;
    }

    /**
     * 校验账号和密码加密
     *
     * @param account
     * @param password
     * @return R<User>
     */
    final R<User> checkUser(String account, String password) {
        //1、从数据库查询比对账号信息
        User user = this.userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getAccount, account));

        //2、密码加密  错误：user.getPassword()
        String passwordMd5 = DigestUtils.md5Hex(password);
        //3、校验数据 比对输入的密码加密后是否正确
        if (user == null || !user.getPassword().equals(passwordMd5)) {
            return R.fail(ExceptionCode.JWT_USER_INVALID);
        }
        return R.success(user);
    }
}
